﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Drawing;
using System.Threading.Tasks;
using System.Windows.Forms;
using LevelEditor.App;
using LevelEditor.App.Serialization;
using LevelEditor.Util;
using LevelEditor.Objects;
using LevelEditor.Objects.Layers;
using LevelEditor.Objects.Tiles;
using LevelEditor.Objects.Waypoints;
using LevelEditor.Components;
using LevelEditor.Components.Layers;
using LevelEditor.Components.Waypoints;


namespace LevelEditor.App
{
    class LoadHelper
    {
        private LayerPanel layerPanel;
        private Library library;
        private LevelEditor editor;

        public LoadHelper(LevelEditor editor, LayerPanel layerPanel, Library library)
        {
            this.editor = editor;
            this.layerPanel = layerPanel;
            this.library = library;
        }

        private void LoadLayers(XmlNode layersNode)
        {
            if (layersNode == null) return;

            XmlNodeList layers = layersNode.ChildNodes;

            XmlSerializer serializer = new XmlSerializer(typeof(SLayer));
            
            for (int k = 0; k < layers.Count; k++)
            {
                MemoryStream stream1 = new MemoryStream();

                byte[] bytes = new byte[layers[k].OuterXml.Length * sizeof(char)];
                System.Buffer.BlockCopy(layers[k].OuterXml.ToCharArray(), 0, bytes, 0, bytes.Length);

                stream1.Write(bytes, 0, bytes.Length);
                stream1.Seek(0, SeekOrigin.Begin);

                SLayer sLayer = (SLayer)serializer.Deserialize(stream1);

                LayerItem item = new LayerItem(editor, sLayer.Name);
                item.Cols = sLayer.Cols;
                item.Rows = sLayer.Rows;
                item.TileHeight = sLayer.TileHeight;
                item.TileWidth = sLayer.TileWidth;

                LoadCharacters(layersNode.SelectSingleNode("layer").SelectSingleNode("Tiles").SelectSingleNode("Characters"), item);
                LoadDoors(layersNode.SelectSingleNode("layer").SelectSingleNode("Tiles").SelectSingleNode("Doors"), item);
                LoadTiles(layersNode.SelectSingleNode("layer").SelectSingleNode("Tiles").SelectSingleNode("CTiles"), item);
                LoadItems(layersNode.SelectSingleNode("layer").SelectSingleNode("Tiles").SelectSingleNode("Items"), item);

                layerPanel.Controls.Add(item);
               
                stream1.Close();
            }

        }

        #region LoadLibrary

        private void LoadCharacters(XmlNode charactersNode, LayerItem item = null)
        {
            if (charactersNode == null) return;

            XmlNodeList characters = charactersNode.ChildNodes;
            try
            {

                XmlSerializer serializer = new XmlSerializer(typeof(SCharacter));
                MemoryStream stream1 = new MemoryStream();

                for (int k = 0; k < characters.Count; k++)
                {
                    byte[] bytes = new byte[characters[k].OuterXml.Length * sizeof(char)];
                    System.Buffer.BlockCopy(characters[k].OuterXml.ToCharArray(), 0, bytes, 0, bytes.Length);

                    stream1.Write(bytes, 0, bytes.Length);
                    stream1.Seek(0, SeekOrigin.Begin);
                    try
                    {

                        SCharacter sCharacter = (SCharacter)serializer.Deserialize(stream1);

                        if (item == null)
                        {
                            Character c = new Character(editor);
                            c.Name = sCharacter.Name;
                            c.Image = Util.Util.Base64ToImage(sCharacter.ImageInfo);
                            this.library.Controls.Add(new LibraryItem(c, editor));
                        }
                        else
                        {
                            Character c = UtilSerialization.ConvertToCharacter(sCharacter, editor);
                            c.MyLayer = item;
                            item.myLayer.Add(c);
                            editor.stage1.Controls.Add(c);
                        }
                    }
                    catch (Exception e)
                    { 
                    
                    }

                }
            }
            catch (Exception e)
            {

            }
        }

        private void LoadDoors(XmlNode doorsNode, LayerItem item = null)
        {
            if (doorsNode == null) return;

            XmlNodeList doors = doorsNode.ChildNodes;

            XmlSerializer serializer = new XmlSerializer(typeof(SDoor));
            MemoryStream stream1 = new MemoryStream();

            for (int k = 0; k < doors.Count; k++)
            {
                byte[] bytes = new byte[doors[k].OuterXml.Length * sizeof(char)];
                System.Buffer.BlockCopy(doors[k].OuterXml.ToCharArray(), 0, bytes, 0, bytes.Length);

                stream1.Write(bytes, 0, bytes.Length);
                stream1.Seek(0, SeekOrigin.Begin);

                SDoor sDoor = (SDoor)serializer.Deserialize(stream1);

                if (item == null)
                {
                    Door c = new Door(editor);
                    c.Name = sDoor.Name;
                    c.Image = Util.Util.Base64ToImage(sDoor.ImageInfo);
                    this.library.Controls.Add(new LibraryItem(c, editor));
                }
                else
                {
                    Door c = UtilSerialization.ConvertToDoor(sDoor, editor);
                    c.MyLayer = item;
                    item.myLayer.Add(c);
                    editor.stage1.Controls.Add(c);
                }
            }
        }

        private void LoadTiles(XmlNode tilesNode, LayerItem item = null)
        {
            if (tilesNode == null) return;

            XmlNodeList ctiles = tilesNode.ChildNodes;

            XmlSerializer serializer = new XmlSerializer(typeof(SCTile));
            MemoryStream stream1 = new MemoryStream();

            for (int k = 0; k < ctiles.Count; k++)
            {
                byte[] bytes = new byte[ctiles[k].OuterXml.Length * sizeof(char)];
                System.Buffer.BlockCopy(ctiles[k].OuterXml.ToCharArray(), 0, bytes, 0, bytes.Length);

                stream1.Write(bytes, 0, bytes.Length);
                stream1.Seek(0, SeekOrigin.Begin);

                SCTile sCTile = (SCTile)serializer.Deserialize(stream1);

                CTile c = new CTile(editor);
                c.Name = sCTile.Name;
                c.Location = new Point(sCTile.PositionX, sCTile.PositionY);
                c.Image = Util.Util.Base64ToImage(sCTile.ImageInfo);

                if (item == null)
                    this.library.Controls.Add(new LibraryItem(c, editor));
                else
                {
                    c.ID = sCTile.ID;
                    c.MyLayer = item;
                    item.myLayer.Add(c);
                    editor.stage1.Controls.Add(c);
                }
            }
        }

        private void LoadItems(XmlNode itemsNode, LayerItem item = null)
        {
            if (itemsNode == null) return;
            
            XmlNodeList items = itemsNode.ChildNodes;

            XmlSerializer serializer = new XmlSerializer(typeof(SItem));
            MemoryStream stream1 = new MemoryStream();

            for (int k = 0; k < items.Count; k++)
            {
                byte[] bytes = new byte[items[k].OuterXml.Length * sizeof(char)];
                System.Buffer.BlockCopy(items[k].OuterXml.ToCharArray(), 0, bytes, 0, bytes.Length);

                stream1.Write(bytes, 0, bytes.Length);
                stream1.Seek(0, SeekOrigin.Begin);

                SItem sItem = (SItem)serializer.Deserialize(stream1);

               /* Item c = new Item(editor);
                c.Name = sItem.Name;
                c.Location = new Point(sItem.PositionX, sItem.PositionX);
                c.Image = Util.Util.Base64ToImage(sItem.ImageInfo);
                c.MyTrigger = sItem.myTrigger;*/

                if (item == null)
                {
                    Item c = new Item(editor);
                    c.Name = sItem.Name;
                    c.Image = Util.Util.Base64ToImage(sItem.ImageInfo);
                    this.library.Controls.Add(new LibraryItem(c, editor));
                }
                else
                {
                    Item c = UtilSerialization.ConvertToItem(sItem, editor);
                    c.MyLayer = item;
                    item.myLayer.Add(c);
                    editor.stage1.Controls.Add(c);
                }
            }
        }

        private void LoadLibrary(XmlNode lib)
        {
            LoadCharacters(lib.SelectSingleNode("Characters"));
            LoadDoors(lib.SelectSingleNode("Doors"));
            LoadTiles(lib.SelectSingleNode("CTiles"));
            LoadItems(lib.SelectSingleNode("Items"));
        }

        #endregion

        public void LoadLevel(string filePath)
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(Cryptography.DecryptStringAES(File.ReadAllText(filePath), Cryptography.SHAREDSECRET));

            LoadLibrary(xmlDoc.GetElementsByTagName("Library").Item(0));
            LoadLayers(xmlDoc.GetElementsByTagName("layers").Item(0));

            SettingWaypointsChars();


            layerPanel.SelectLayer((LayerItem)layerPanel.Controls[0]);
        }

        private void SettingWaypointsChars()
        {
            foreach (Control c in editor.stage1.Controls)
            {
                if ((c as Character) == null) continue;

                foreach(WaypointsCollection wayColl in UtilSerialization.allWaypointsCollections)
                {
                    foreach (Waypoint way in wayColl.FindAll(delegate(Waypoint w) { return (w.idCharacter == (c as Character).ID);  }))
                    {
                        way.character = (Character)c;
                    }

                }
            }
        }
    }
}
